<template>
  <input
    ref="fileEle"
    class="avatar-upload"
    type="file"
    accept="image/*"
    @change="handleToFiles"
  />
  <slot></slot>
</template>

<script lang="ts" setup>
import { ref } from "vue";
import { dataURItoBlob } from "@/plugins/pictureProcess";
import { ElMessage } from "element-plus";
import { compress } from "image-conversion";

const props = defineProps<{
  action: string;
}>();

const emits = defineEmits<{
  (e: "start"): void;
  (e: "success", src: string): void;
  (e: "error"): void;
}>();

// 给input属性一个ref属性
const fileEle = ref<HTMLInputElement>();

/**
 * 监听用户是否已经上传了头像
 */
const handleToFiles: () => void = (): void => {
  const fileList: FileList = fileEle.value?.files as FileList;
  // 判断文件的大小是否小于12MB
  const is12M = fileList[0].size / 1024 / 1024 < 12;
  if (!is12M) {
    // 如果大于4MB则报错直接返回
    ElMessage.error("上传的头像文件大小不能大于12MB");
    return;
  }
  /**
   * 读取文件内容
   */
  const reader: FileReader = new FileReader();
  // 该事件在读取操作完成时触发。
  reader.onload = async (e: ProgressEvent<FileReader>) => {
    let form: FormData = new FormData();
    const img: string = e.target?.result as string;
    let imgBlob: Blob = dataURItoBlob(img);
    // 如果图片大于0.5MB的话则压缩图片
    if (fileList[0].size / 1024 / 1024 > 0.5) {
      const value: Blob = await compress(fileList[0], 0.25);
      imgBlob = value;
    }
    form.append("avatarFile", imgBlob);
    emits("start");
    // 开始发送请求
    fetch(props.action, {
      method: "post",
      body: form,
    })
      .then((res) => res.json())
      .then((res) => {
        if (res.code === 1) emits("success", res.data.avatarSrc);
        else {
          emits("error");
          console.log(res.msg);
        }
      })
      .catch((error) => {
        console.log(error);
        emits("error");
      });
  };
  // 读取指定的Blob或File对象
  reader.readAsDataURL(fileList[0]);
};

/**
 * 准备上传头像(打开windows文件接口)
 */
const upload = (): void => fileEle.value?.click();

defineExpose({
  upload,
});
</script>

<style lang="scss" scoped>
.avatar {
  &-upload {
    display: none;
  }
}
</style>
